home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / mskrmsrc.zip / MSSCOM.ASM < prev    next >
Assembly Source File  |  1991-10-24  |  60KB  |  1,744 lines

  1.     NAME    msscom
  2. ; File MSSCOM.ASM
  3.     include mssdef.h
  4. ;       Copyright (C) 1982,1991, Trustees of Columbia University in the
  5. ;       City of New York.  Permission is granted to any individual or
  6. ;       institution to use, copy, or redistribute this software as long as
  7. ;       it is not sold for profit and this copyright notice is retained.
  8. ; Edit history:
  9. ; 6 Sept 1991 version 3.11
  10. ; 2 March 1991 version 3.10
  11. ; Last edit 6 Sept 1991
  12.  
  13.     public    spack, rpack, sleep, spause, bufclr, pakptr, bufrel
  14.     public    makebuf, getbuf, pakdup, chkwind, firstfree, windused
  15.     public    rpacket, windlow, chkparflg
  16.  
  17. stat_suc equ    0        ; success
  18. stat_tmo equ    1        ; timeout
  19. stat_chk equ    2        ; checksum mismatch
  20. stat_ptl equ    4        ; packet too long
  21. stat_int equ    8        ; user interrupt
  22. stat_eol equ    10h        ; eol char seen
  23. stat_bad equ    80h        ; packet is bad (premature EOL)
  24.  
  25. data    segment
  26.     extrn    flags:byte, trans:byte, fsta:word, ssta:word, fmtdsp:byte
  27.     extrn    pktnum:byte, portval:word, denyflg:word
  28.  
  29. parmsk    db    0ffh        ; parity mask (0FFH for 8bit data path) [umd]
  30. badpflag db    0        ; flag to say have shown bad parity message
  31. spmes    db    'Spack: $'
  32. rpmes     db    'Rpack: $'
  33. crlf    db      cr,lf,'$'
  34. msgstl    db    'Internal Error: send packet is too long',0,'$'
  35. msgtmo    db    '<Timeout>',cr,lf,'$'
  36. msgbad    db    '<Crunched packet>',cr,lf,'$'
  37. msgecho    db    '<Echo of sent packet>',cr,lf,'$'
  38. msgbadsnd db    cr,lf,'<Error sending packet bytes>',cr,lf,'$'
  39. msgbadpare db    'Unexpected Parity from host! Changing Parity to EVEN'
  40.     db    cr,lf,0
  41. msgbadparo db    'Unexpected Parity from host! Changing Parity to ODD'
  42.     db    cr,lf,0
  43. msgbadparm db    'Unexpected Parity from host! Changing Parity to MARK'
  44.     db    cr,lf,0
  45. tmp    db    0
  46. spause    db    0        ; # millisec to wait before sending pkt
  47. timeval    db    0        ; active receive timeout value, seconds
  48. prvtyp  db      0        ; Type of last packet sent
  49. chkparflg db    0        ; non-zero to check parity on received pkts
  50. prevchar db    0        ; previous char from comms line (for ^C exit)
  51. lentyp    db    0        ; packet length type, 3, 0, 1
  52. debflg    db    0        ; debug display, send/receive flag
  53. timeit    db    0        ; arm timeout counter
  54. flowon    db    0        ; xon or null, flow-on value
  55.                 ; sliding windows data structures
  56. windlow    db    0        ; lower border of window
  57. windused db    0        ; number of window slots in use
  58. prolog  db    10 dup (0)    ; prolog: SOH, LEN, SEQ, TYPE, xlen,...,null
  59. epilog    db    30 dup (0)    ; epilog: checksum, eol, handshake + null term
  60. rbuf    db    128 dup (0)    ; static packet buffer for replies
  61.     even
  62. bufnum    dw    0        ; number of buffers available now
  63. buflist dw    maxwind dup (0) ; pointers to packet structures in pktlist
  64. bufuse    dw    maxwind dup (0) ; in-use flag (0 = not in use)
  65. pktlist    pktinfo maxwind dup (<>) ; pktinfo structured members (private)
  66. bufbuf    db    maxpack+((3*maxwind)/2) dup (0) ; Data buffer for packets
  67. rpacket    pktinfo <offset rbuf,0,length rbuf,0,0> ; reply pktinfo
  68.     even
  69. rtemp    dw    0        ; address of pktinfo structure for rpack
  70. stemp    dw    0        ; address of pktinfo structure for spack
  71. linecnt    dw    0        ; debug line width counter
  72. pktptr  dw    0        ; position in receive packet
  73. chksum    dw    0        ; running checksum (two char)
  74. chrcnt    dw    0        ; number of bytes in data field of a packet
  75. spkcnt    dw    0        ; number of bytes sent in this packet
  76. rpkcnt    dw    0        ; number of bytes received in this packet
  77. status    dw    0        ; status of packet receiver (0 = ok)
  78. deblen    dw    0        ; length of current debug buffer
  79. fairflg    dw    0        ; fairness flag, for console/port reads
  80. time     dw    2 dup (0)    ; Sleep, when we should timeout
  81. rptim    db    4 dup (0)    ; read packet timeout slots
  82. sixzero    dw    60        ; for div operation in rec packet timeouts
  83. ninefive dw    95        ; for mult/div with long packets
  84. temp    dw    0
  85. data    ends
  86.  
  87. code    segment
  88.     extrn    prtchr:near, outchr:near, isdev:near
  89.     extrn    sppos:near, ermsg:near, clearl:near, rppos:near
  90.     extrn    pktcpt:near, strlen:near, pcwait:near
  91.  
  92.     assume     cs:code, ds:data, es:nothing
  93. prtchr1    proc    far        ; near-far interface routines for code1 seg
  94.     call    prtchr
  95.     ret
  96. prtchr1    endp
  97. outchr1    proc    far
  98.     call    outchr
  99.     ret
  100. outchr1    endp
  101. isdev1    proc    far
  102.     call    isdev
  103.     ret
  104. isdev1    endp
  105. rppos1    proc    far
  106.     call    rppos
  107.     ret
  108. rppos1    endp
  109. sppos1    proc    far
  110.     call    sppos
  111.     ret
  112. sppos1    endp
  113. ermsg1    proc    far
  114.     call    ermsg
  115.     ret
  116. ermsg1    endp
  117. clearl1    proc    far
  118.     call    clearl
  119.     ret
  120. clearl1    endp
  121. pktcpt1    proc    far
  122.     call    pktcpt
  123.     ret
  124. pktcpt1    endp
  125. strlen1    proc    far
  126.     call    strlen
  127.     ret
  128. strlen1    endp
  129. pcwait1    proc    far
  130.     call    pcwait
  131.     ret
  132. pcwait1    endp
  133. code    ends
  134.  
  135. code1    segment
  136.     assume     cs:code1, ds:data, es:nothing
  137.  
  138. ; Send_Packet
  139. ; This routine assembles a packet from the arguments given and sends it
  140. ; to the host.
  141. ;
  142. ; Expects the following:
  143. ;    SI = pointer to pktinfo structure, as
  144. ;    [SI].PKTYPE - Packet type letter
  145. ;    [SI].SEQNUM - Packet sequence number
  146. ;    [SI].DATLEN - Number of data characters
  147. ;    [SI].DATADR - Address of data field for packet
  148. ; Returns: carry clear if success, carry set if failure.
  149. ; Packet construction areas:
  150. ;     Prolog (8 bytes)            Data     null  Epilog
  151. ;+----------------------------------------+---------------+---------------+
  152. ;| SOH,LEN,SEQ,TYPE,Xlen(2-3),Xlen chksum | packet's data | chksum,EOL,HS |
  153. ;+----------------------------------------+---------------+---------------+
  154. ; where Xlen is 2 byte (Long) or 3 byte (Extra Long) count of bytes to follow.
  155. ;
  156. SPACK    PROC    FAR
  157.     mov    stemp,si    ; save pkt pointer
  158.     mov    ah,[si].pktype
  159.     mov    prvtyp,ah    ; remember packet type
  160.     mov    spkcnt,0    ; number of bytes sent in this packet
  161.     add    fsta.pspkt,1    ; statistics, count a packet being sent
  162.     adc    fsta.pspkt+2,0    ;  ripple carry
  163.     add    ssta.pspkt,1    ; statistics, count a packet being sent
  164.     adc    ssta.pspkt+2,0    ;  ripple carry
  165.     mov    al,spause    ; wait spause milliseconds before sending pkt
  166.     or    al,al        ; zero?
  167.     jz    spac1        ; z = yes
  168.     xor    ah,ah
  169.     call    pcwait1        ;   to let other side get ready
  170. spac1:    mov    cl,trans.spad    ; get the number of padding chars
  171.     xor    ch,ch
  172.     jcxz    spac4        ; z = none
  173.     xor    al,al
  174.     xchg    al,trans.sdbl    ; doubling char, stash and clear it
  175.     push    ax
  176.     mov    ah,trans.spadch    ; get padding char
  177. spac2:    call    spkout        ; send padding char
  178.     jnc    spac3        ; nc = success
  179.     ret            ; failed
  180. spac3:    loop    spac2
  181.     pop    ax        ; recover doubling char
  182.     xchg    trans.sdbl,al
  183.  
  184. spac4:    mov    bx,offset prolog ; start with these guys
  185.     mov    pktptr,bx
  186.     call    snddeb        ; do debug display (while it's still our turn)
  187.     mov    bx,offset prolog ; start with these guys
  188.     mov    pktptr,bx
  189.     push    es
  190.     push    ds
  191.     pop    es
  192.     cld
  193.     mov    cx,length prolog
  194.     mov    di,offset prolog
  195.     xor    al,al
  196.     rep    stosb
  197.     mov    cx,length epilog
  198.     mov    di,offset epilog
  199.     rep    stosb
  200.     pop    es
  201.     mov    al,trans.ssoh    ; get the start of header char
  202.     mov    prolog,al    ; put SOH in the packet
  203.     mov    si,stemp    ; address of send pktinfo
  204.     mov    al,[si].seqnum    ; SEQ
  205.     add    al,20h        ; ascii bias
  206.     mov    prolog+2,al    ; store SEQ in packet
  207.     xor    ah,ah
  208.     mov    chksum,ax    ; start checksum
  209.     mov    al,prvtyp    ; TYPE
  210.     mov    prolog+3,al    ; store TYPE
  211.     add    chksum,ax    ; add to checksum
  212. ;
  213. ; packet length type is directly governed here by length of header plus data
  214. ; field, [si].datlen, plus chksum: regular <= 94, long <= 9024, else X long.
  215. ;
  216.     mov    ax,[si].datlen    ; DATA length
  217.     add    ax,2        ; add SEQ, TYPE lengths
  218.     add    al,trans.chklen    ; add checksum length at the end
  219.     adc    ah,0        ; propagate carry, yields overall new length
  220.     cmp    ax,[si].datsize    ; too big?
  221.     jle    spac14        ; le = ok
  222.     push    dx        ; tell user an internal error has occurred
  223.     mov    dx,offset msgstl ; packet is too long
  224.     call    ermsg1        ; display message on error line
  225.     call    captdol        ; put into packet log
  226.     pop    dx
  227.     stc
  228.     ret            ; return bad
  229.  
  230. spac14:    mov    lentyp,3    ; assume regular packet
  231.     cmp    ax,94        ; longer than a regular?
  232.     ja    spac15        ; a = use Long
  233.     add    al,20h        ; convert length to ascii
  234.     mov    prolog+1,al    ; store LEN
  235.     xor    ah,ah
  236.     add    chksum,ax    ; add LEN to checksum
  237.     mov    bx,offset prolog+4 ; look at data field
  238.     jmp    spac19        ; do regular
  239.  
  240.                 ; use Long packets (type 0)
  241. spac15:    sub    ax,2        ; deduct SEQ and TYPE from above = data+chksum
  242.     mov    lentyp,0    ; assume type 0 packet
  243.     cmp    ax,(95*95-1)    ; longest type 0 Long packet (9024)
  244.     jbe    spac16        ; be = type 0
  245.     mov    lentyp,1    ; type 1 packet, Extra Long
  246. spac16:    mov    cl,lentyp    ; add new LEN field to checksum
  247.     add    cl,20h        ; ascii bias, tochar()
  248.     xor    ch,ch
  249.     add    chksum,cx    ; add to running checksum
  250.     mov    prolog+1,cl    ; put LEN into packet
  251.     mov    bx,offset prolog+4
  252.     mov    cx,1        ; a counter
  253.     xor    dx,dx        ; high order numerator of length
  254. spac17:    div    ninefive    ; divide ax by 95. quo = ax, rem = dx
  255.     push    dx        ; push remainder
  256.     inc    cx        ; count push depth
  257.     cmp    ax,95        ; quotient >= 95?
  258.     jae    spac17        ; ae = yes, recurse
  259.     push    ax        ; push for pop below
  260. spac18:    pop    ax        ; get a digit
  261.     add    al,20h        ; apply tochar()
  262.     mov    [bx],al        ; store in data field
  263.     add    chksum,ax    ; accumulate checksum for header
  264.     inc    bx        ; point to next data field byte
  265.     mov    byte ptr[bx],0    ; insert terminator
  266.     loop    spac18        ; get the rest
  267.                 ;
  268.     mov    ax,chksum    ; current checksum
  269.     shl    ax,1        ; put two highest bits of al into ah
  270.     shl    ax,1
  271.     and    ah,3        ; want just those two bits
  272.     shr    al,1        ; put al back in place
  273.     shr    al,1
  274.     add    al,ah        ; add two high bits to earlier checksum
  275.     and    al,03fh        ; chop to lower 6 bits (mod 64)
  276.     add    al,20h        ; apply tochar()
  277.     mov    [bx],al        ; store that in length's header checksum
  278.     inc    bx
  279.     mov    byte ptr [bx],0 ; terminator to prolog field
  280.     xor    ah,ah
  281.     add    chksum,ax    ; add that byte to running checksum
  282.                 ; end of inserting Long pkt info
  283.  
  284. spac19:    mov    cx,bx        ; where we stopped+1
  285.     mov    bx,offset prolog ; place where prolog section starts
  286.     sub    cx,bx
  287.     jcxz    spac22        ; nothing
  288. spac20:    mov    ah,[bx]        ; prolog part
  289.     or    ah,ah        ; at the end?
  290.     jz    spac22        ; z = yes
  291.     inc    bx
  292.     call    spkout        ; send byte to serial port
  293.     jnc    spac21        ; nc = good send
  294.     jmp    spac28        ; bad send
  295. spac21:    loop    spac20        ; do all prolog parts
  296. spac22:    mov    pktptr,offset prolog ; starting point for deblin, end = [bx-1]
  297.     call    deblin        ; show debug info for prolog
  298.     mov    si,stemp    ; address of pktinfo
  299.     mov    bx,[si].datadr    ; select from given data buffer
  300.     mov    pktptr,bx    ; start here with next deblin
  301.     mov    dx,[si].datlen    ; get the number of data bytes in packet
  302. spac23:    or    dx,dx        ; any data chars remaining?
  303.     jle    spac25        ; le = no, finish up
  304.     mov    al,[bx]        ; get a data char
  305.     inc    bx        ; point to next char [umd]
  306. spac24:    xor    ah,ah
  307.     add    chksum,ax    ; add the char to the checksum [umd]
  308.     and    chksum,0fffh    ; keep only low order 12 bits
  309.     mov    ah,al        ; put char in ah where spkout wants it
  310.     dec    dx        ; say sending one character
  311.     call    spkout        ; send it
  312.     jnc    spac23        ; nc = success, get more data chars
  313.     jmp    spac28        ; bad send
  314.  
  315. spac25:    mov    byte ptr [bx],0    ; terminator of data field
  316.     call    deblin        ; show debug display of data field
  317.     mov    bx,offset epilog ; area for epilog
  318.     mov    pktptr,bx    ; where to start last of debug display
  319.     mov    cx,chksum
  320.     cmp    trans.chklen,2    ; what kind of checksum are we using?
  321.     je    spac27        ; e = 2 characters
  322.     jg    spac26        ; g = 3 characters
  323.     mov    ah,cl        ; 1 char: get the character total
  324.     mov    ch,cl        ; save here too (need 'cl' for shift)
  325.     and    ah,0C0H        ; turn off all but the two high order bits
  326.     mov    cl,6
  327.     shr    ah,cl        ; shift them into the low order position
  328.     mov    cl,ch
  329.     add    ah,cl        ; add it to the old bits
  330.     and    ah,3FH        ; turn off the two high order bits.  (MOD 64)
  331.     add    ah,' '        ; add a space so the number is printable
  332.     mov    [bx],ah        ; put in the packet
  333.     inc    bx        ; point to next char
  334.     call    spkout        ; send it
  335.     jnc    spac30        ; add EOL char
  336.     jmp    spac28        ; bad send
  337. spac26: mov    byte ptr[bx],0    ; null, to determine end of buffer
  338.     push    bx        ; don't lose our place
  339.     mov    bx,offset prolog+1 ; first checksummed char, skip SOH
  340.     xor    dx,dx        ; initial CRC value is 0
  341.     call    crcclc        ; calculate the CRC of prolog part, to cx
  342.     mov    si,stemp    ; address of pktinfo
  343.     mov    bx,[si].datadr    ; address of data
  344.     push    bx        ; save address
  345.     add    bx,[si].datlen    ; byte beyond data
  346.     mov    byte ptr [bx],0    ; null terminator for CRC
  347.     pop    bx        ; recover address of data
  348.     mov    dx,cx        ; first part of CRC returned in cx
  349.     call    crcclc        ; do CRC of data, using current CRC in dx
  350.     pop    bx        ; recover place to store more debug info
  351.     push    cx        ; save the crc
  352.     mov    ax,cx        ; manipulate it here
  353.     and    ax,0F000H    ; get 4 highest bits
  354.     mov    cl,4
  355.     shr    ah,cl        ; shift over 4 bits
  356.     add    ah,' '        ; make printable
  357.     mov    [bx],ah        ; add to buffer
  358.     inc    bx
  359.     pop    cx        ; get back checksum value
  360.     call    spkout        ; send it
  361.     jnc    spac27
  362.     jmp    short spac28    ; bad send
  363. spac27:    push    cx        ; save it for now
  364.     and    cx,0FC0H    ; get bits 6-11
  365.     mov    ax,cx
  366.     mov    cl,6
  367.     shr    ax,cl        ; shift them bits over
  368.     add    al,' '        ; make printable
  369.     mov    [bx],al        ; add to buffer
  370.     inc    bx
  371.     mov    ah,al
  372.     call    spkout        ; send it
  373.     pop    cx        ; get back the original
  374.     jc    spac28        ; c = bad send
  375.     and    cx,003FH    ; get bits 0-5
  376.     add    cl,' '        ; make printable
  377.     mov    [bx],cl        ; add to buffer
  378.     inc    bx
  379.     mov    ah,cl
  380.     call    spkout        ; send it
  381.     jnc    spac30
  382. spac28:    call    deblin        ; show debug info so far before exiting
  383.     mov    dx,offset msgbadsnd ; say sending error in log
  384.     call    captdol
  385.     mov    si,stemp    ; restore pkt pointer
  386.     stc            ; carry set for failure
  387.     RET            ; bad send, do ret to caller of spack
  388.  
  389. spac30:    mov    ah,trans.seol    ; get the EOL the other host wants
  390.     mov    [bx],ah        ; put eol
  391.     inc    bx
  392.     call    deblin        ; do debug display (while it's still our turn)
  393.     test    flags.debug,logpkt ; In debug mode?
  394.     jnz    spac31        ; nz = yes
  395.     test    flags.capflg,logpkt ; log packets?
  396.     jz    spac32        ; z = no
  397. spac31:    cmp    linecnt,0    ; anything on current line?
  398.     je    spac32        ; e = no
  399.     mov    dx,offset crlf    ; finish line with cr/lf
  400.     call    captdol        ;  to log file
  401. spac32:    mov    ah,trans.seol    ; recover EOL
  402.     call    spkout        ; send it
  403.     jnc    spac33
  404.     stc            ; bad send
  405.     ret            ; return in error state
  406.  
  407. spac33:    mov    ax,spkcnt    ; number of bytes sent in this packet
  408.     add    fsta.psbyte,ax    ; file total bytes sent
  409.     adc    fsta.psbyte+2,0    ; propagate carry to high word
  410.     add    ssta.psbyte,ax    ; for session
  411.     adc    ssta.psbyte+2,0
  412.     call    chkcon        ; check console for user interrupts
  413.     mov    si,stemp    ; restore pkt pointer
  414.     clc            ; carry clear for success
  415.     ret            ; return successfully
  416. SPACK    ENDP 
  417.  
  418. spkout:    cmp    ah,trans.sdbl    ; double this char?
  419.     jne    spkou1        ; ne = no
  420.     call    spkou1        ; do it once here and again via fall through
  421.     jnc    spkou1        ;  but again only if no failure
  422.     ret            ; return failure
  423. spkou1:    push    ax        ; send char in ah out the serial port
  424.     push    bx        ; return carry clear if success
  425.     push    cx
  426.     push    dx
  427.     mov    tmp,1        ; retry counter
  428. spkour:    call    outchr1        ; serial port transmitter procedure
  429.     jc    spkoux        ; c = bad send, retry
  430.     inc    spkcnt        ; count number of bytes sent in this packet
  431.     pop    dx
  432.     pop    cx
  433.     pop    bx
  434.     pop    ax
  435.     clc            ; carry    clear for good send
  436.     ret
  437. spkoux:    cmp    tmp,5        ; done 5 attempts on this char?
  438.     jge    spkoux1        ; ge = yes, fail the sending
  439.     inc    tmp
  440.     push    ax
  441.     mov    ax,10        ; wait 10 milliseconds
  442.     call    pcwait1
  443.     pop    ax
  444.     jmp    short spkour    ; retry
  445. spkoux1:pop    dx        ; failed to send char
  446.     pop    cx
  447.     pop    bx
  448.     pop    ax
  449.     stc            ; set carry for bad send
  450.     ret
  451.      
  452. ; Calculate the CRC of the null-terminated string whose address is in BX.
  453. ; Returns the CRC in CX.  Destroys BX and AX.
  454. ; The CRC is based on the SDLC polynomial: x**16 + x**12 + x**5 + 1.
  455. ; By Edgar Butt  28 Oct 1987 [ebb].
  456. ; Enter with initial CRC in DX (normally 0).
  457. crcclc: push    dx
  458.     mov    cl,4            ; load shift count
  459. crc0:   mov    ah,[bx]            ; get the next char of the string
  460.         or    ah,ah            ; if null, then we're done
  461.         jz    crc1            ; z = null, stop
  462.         inc    bx
  463.         xor    dl,ah            ; XOR input with lo order byte of CRC
  464.         mov    ah,dl            ; copy it
  465.         shl    ah,cl            ; shift copy
  466.         xor    ah,dl            ; XOR to get quotient byte in ah
  467.         mov    dl,dh            ; high byte of CRC becomes low byte
  468.         mov    dh,ah            ; initialize high byte with quotient
  469.         xor    al,al
  470.         shr    ax,cl            ; shift quotient byte
  471.         xor    dl,ah            ; XOR (part of) it with CRC
  472.         shr    ax,1            ; shift it again
  473.         xor    dx,ax            ; XOR it again to finish up
  474.         jmp    short crc0
  475. crc1:   mov    cx,dx            ; return CRC in CX
  476.         pop    dx
  477.         ret
  478.  
  479. ; Receive_Packet
  480. ; This routine waits for a packet arrive from the host. Two Control-C's in a
  481. ; row from the comms line will cause a Control-C interruption exit.
  482. ; Returns
  483. ;    SI = pointer to pktinfo structure, as
  484. ;    [SI].SEQNUM - Packet sequence number
  485. ;    [SI].DATLEN - Number of data characters
  486. ;    [SI].DATADR - Address of data field for packet
  487. ; Returns AH -  packet type (letter code)
  488. ; Returns: carry clear if success, carry set if failure.
  489. ; Packet construction areas:
  490. ;     Prolog (8 bytes+2 nulls)    null    Data    null  Epilog   null
  491. ;+----------------------------------------+---------------+---------------+
  492. ;| SOH,LEN,SEQ,TYPE,Xlen(2-3),Xlen chksum | packet's data | chksum,EOL,HS |
  493. ;+----------------------------------------+---------------+---------------+
  494. ; where Xlen is 2 byte (Long) or 3 byte (Extra Long) count of bytes to follow.
  495.  
  496. RPACK    PROC    FAR
  497.     mov    rtemp,si        ; save pkt structure address
  498.     xor    ax,ax            ; get a zero
  499.     mov    debflg,al        ; say debugging display not setup
  500.     mov    fairflg,ax        ; set fairness flag
  501.     mov    badpflag,al        ; bad parity flag, clear it
  502.     mov    prevchar,al        ; clear previous recv'd char area
  503.     mov    [si].pktype,'T'        ; assume 'T' type packet (timeout)
  504.     mov    bx,[si].datadr        ; caller's data buffer
  505.     mov    pktptr,bx        ; debug buffer pointer for new stuff
  506.     mov    [si].datlen,ax        ; init to empty buffer
  507.     mov    cx,[si].datsize        ; length of that buffer, for debugger
  508.     mov    deblen,cx
  509.     mov    word ptr [bx],ax    ; clear storage areas (asciiz)
  510.     mov    word ptr prolog,ax
  511.     mov    word ptr epilog,ax
  512.     mov    cl,trans.stime        ; time to wait for start of packet
  513.     mov    timeval,cl        ; local timer value, seconds
  514.     mov    status,stat_suc        ; assume success
  515.     mov    rpkcnt,ax        ; number of bytes rcvd in packet
  516.     push    bx
  517.     mov    parmsk,0ffh        ; parity mask, assume 8 bit data
  518.     mov    bx,portval
  519.     mov    ax,[bx].flowc        ; flow control
  520.     mov    flowon,al        ; xon or null
  521.     xor    ax,ax
  522.     cmp    [bx].parflg,parnon    ; parity is none?
  523.     pop    bx
  524.     je    rpack0a            ; e = none
  525.     mov    parmsk,7fh        ; else strip parity (8th) bit
  526.     jmp    rpack0a
  527.  
  528.                     ; get here with unexpected char
  529. rpack0:    test    status,stat_tmo        ; timeout get us here?
  530.     jnz    rpack0f            ; nz = yes, no new char to record
  531.     xor    ah,ah
  532.     mov    [bx],ax            ; store 8 bit char in buffer
  533.     inc    bx            ; advance buffer pointer
  534. rpack0f:push    ax            ; save around this work
  535.     cmp    debflg,0        ; started debugging display yet?
  536.     jne    rpack0d            ; ne = yes
  537.     call    rcvdeb            ; setup receive debug display
  538. rpack0d:call    deblin            ; debug, show chars received thus far
  539.     mov    bx,rtemp        ; pktinfo address
  540.     mov    [bx].datlen,0        ; say no data yet
  541.     mov    [bx].seqnum,0ffh    ; illegal value
  542.     mov    [bx].pktype,0        ; illegal value
  543.     mov    ax,[bx].datsize     ; length of that buffer, for debugger
  544.     mov    deblen,ax
  545.     mov    bx,[bx].datadr        ; data field address, reuse for prolog
  546.     mov    pktptr,bx        ; debug buffer pointer for new stuff
  547.     xor    ax,ax
  548.     mov    word ptr [bx],ax     ; clear the data field
  549.     mov    word ptr prolog,ax    ; clear prolog field
  550.     mov    word ptr epilog,ax    ; clear epilog field
  551.     mov    rpkcnt,ax        ; count of chars
  552.     pop    ax            ; recover unexpected char
  553.     test    status,stat_int        ; interrupted?
  554.     jz    rpack0e            ; z = no
  555.     jmp    rpack60            ; yes, exit now
  556. rpack0e:mov    status,stat_suc        ; assume success
  557.     and    al,7fh            ; strip high bit
  558.     cmp    al,trans.rsoh        ; was unexpected char the SOH?
  559.     je    rpack1            ; e = yes, get LEN char
  560.  
  561. rpack0a:call    inchr            ; get a character. SOH
  562.     jnc    rpack0b            ; nc = got one
  563.                 ; c=failure (eol, timeout, user intervention)
  564.     test    status,stat_eol        ; hit eol from prev packet?
  565.     jnz    rpack0            ; nz = yes, restart
  566.     jmp    rpack60            ; timeout or user intervention
  567.  
  568. rpack0b:mov    ah,al            ; copy the char
  569.     and    ah,7fh            ; strip any parity bit, regardless
  570.     cmp    ah,trans.rsoh        ; start of header char?
  571.     je    rpack0c            ; e = yes, SOH
  572.     jmp    rpack0            ; ne = no, go until it is
  573. rpack0c:xor    ah,ah            ; clear the terminator byte
  574.     mov    [bx],ax            ; store 8 bit char in buffer
  575.     inc    bx            ; advance buffer pointer
  576. rpack1:    mov    timeval,2        ; reduce local timer value to 2 secs
  577.     call    inchr            ; get a character. LEN
  578.     jc    rpack1a            ; failure
  579.     mov    [bx],al            ; store LEN in buffer
  580.     and    al,7fh            ; strip any parity bit
  581.     cmp    al,trans.rsoh        ; start of header char?
  582.     jne    rpack1b            ; ne = no
  583. rpack1a:jmp    rpack0            ; yes, start over (common jmp point)
  584. rpack1b:inc    bx
  585.     mov    chksum,ax        ; start the checksum
  586.     sub    al,20h            ; unchar(LEN) to binary
  587.     jnc    rpack1e            ; nc = legal (printable)
  588.     mov    status,stat_ptl        ; set bad length status
  589.     jmp    rpack40            ; and quit
  590. rpack1e:mov    si,rtemp
  591.     mov    [si].datlen,ax        ; save the data count (byte)
  592.     call    inchr            ; get a character. SEQ
  593.     jc    rpack1a            ; c = failure
  594.     mov    [bx],al            ; store SEQ in buffer
  595.     inc    bx
  596.     and    al,7fh            ; strip any parity bit
  597.     cmp    al,trans.rsoh        ; SOH?
  598.     je    rpack1a            ; e = yes, then go start over
  599.     add    chksum,ax
  600.     sub    al,' '            ; get the real packet number
  601.     jnc    rpack1f            ; nc = no overflow
  602.     mov    status,stat_ptl        ; say bad status
  603.     jmp    rpack40            ; and exit now
  604. rpack1f:mov    si,rtemp
  605.     mov    [si].seqnum,al        ; save the packet number. SEQ
  606.     call    inchr            ; get a character. TYPE
  607.     jc    rpack1a            ; c = failure
  608.     mov    [bx],al            ; store TYPE in buffer
  609.     inc    bx
  610.     and    al,7fh            ; strip any parity bit
  611.     cmp    al,trans.rsoh        ; SOH?
  612.     je    rpack1a            ; e = yes, then go start over
  613.     mov    [si].pktype,al        ; save the message type
  614.     add    chksum,ax        ; add it to the checksum
  615.     call    parchk            ; check parity on protocol characters
  616.     call    getlen        ; get complicated data length (reg, lp, elp)
  617.                 ; into [si].datlen and kind into byte lentyp. carry set if error
  618.     jnc    rpack1c            ; nc = packet is ok so far
  619.     jmp    rpack40            ; failure
  620. rpack1c:
  621. ; Start of change.
  622. ; Now determine block check type for this packet.  Here we violate the layered
  623. ; nature of the protocol by inspecting the packet type in order to detect when
  624. ; the two sides get out of sync.  Two heuristics allow us to resync here:
  625. ;   a. I and S packets always has a type 1 checksum.
  626. ;   b. A NAK never contains data, so its block check type is seqnum1.
  627.     mov    si,rtemp        ; pktinfo address
  628.     mov    ax,[si].datlen        ; length of packet information
  629.     mov    cl,[si].pktype        ; packet type byte itself
  630.     cmp    cl,'S'            ; "S" packet?
  631.     jne    rpk0            ; ne = no
  632.     mov    trans.chklen,1        ; S packets use one byte checksums
  633.     jmp    short rpk3
  634. rpk0:    cmp    cl,'I'            ; I packets are like S packets
  635.     jne    rpk1
  636.     mov    trans.chklen,1        ; I packets use one byte checksums
  637.     jmp    short rpk3
  638. rpk1:    cmp    cl,'N'            ; NAK?
  639.     jne    rpk3            ; ne = no
  640.     cmp    ax,1            ; NAK, get length of data + chklen
  641.     jb    rpk1a            ; b = impossible length
  642.     cmp    ax,3            ; longest NAK (3 char checksum)
  643.     jbe    rpk2            ; be = possible
  644. rpk1a:    or    status,stat_ptl        ; status = bad length
  645.     jmp    rpack40            ; return on impossible length
  646. rpk2:    mov    trans.chklen,al        ; remainder must be checksum type for NAK
  647. rpk3:    sub    al,trans.chklen        ; minus checksum length, for all pkts
  648.     sbb    ah,0            ; propagate borrow
  649.     mov    [si].datlen,ax        ; store apparent length of data field
  650. ; End of change.
  651. ; now, for long packets we start the real data (after the extended byte
  652. ; count 3 or 4 bytes) at offset data and thus the checksumming starts
  653. ; such packets a few bytes earlier.
  654.     push    si
  655.     push    di
  656.     mov    si,rtemp        ; pktinfo address
  657.     mov    si,[si].datadr        ; data field address
  658.     mov    di,offset prolog    ; where to store
  659.     mov    cx,4            ; number of bytes to move, reg pkts
  660.     cmp    lentyp,0        ; long packets?
  661.     jne    rpk5            ; ne = no
  662.     mov    cx,7            ; seven bytes mark...type, xl,xl,xlchk
  663.     jmp    short rpk7
  664. rpk5:    cmp    lentyp,1        ; extra long packets?
  665.     jne    rpk7            ; ne = no
  666.     mov    cx,8            ; extra long packets
  667. rpk7:    push    es            ; save es
  668.     push    ds
  669.     pop    es            ; set es to data segment
  670.     cld                ; move forward
  671.     rep    movsb            ; move the protocol header, cx times
  672.     mov    byte ptr [di],0     ; null terminator
  673.     pop    es
  674.     pop    di
  675.     pop    si
  676.  
  677.     mov    si,rtemp
  678.     push    si
  679.     mov    si,[si].datadr
  680.     mov    word ptr [si],0        ; clear data field for debugging
  681.     pop    si
  682.     mov    dx,[si].datlen        ; length of data field, excl LP header
  683.     mov    chrcnt,dx
  684.     cmp    dx,[si].datsize        ; material longer than data buffer?
  685.     ja    rpk8b            ; a = yes, give up
  686.     mov    dx,trans.rlong        ; longest packet we should receive
  687.     sub    dl,trans.chklen        ; minus checksum length
  688.     sbb    dh,0            ; propagate borrow
  689.     cmp    dx,chrcnt        ; is data too long?
  690.     jae    rpk8c            ; ae = not too big
  691.     or    status,stat_ptl        ; failure status, packet too long
  692. rpk8b:    jmp    rpack40            ; too big, quit now
  693. rpk8c:    mov    bx,[si].datadr        ; point to the data buffer
  694.     mov    pktptr,bx        ; start of buffer for debugging
  695.     mov    dx,[si].datsize     ; length of that buffer, for debugger
  696.     mov    deblen,dx        ; keep here
  697.     mov    word ptr [bx],0        ; clear start of that buffer
  698.                     ; get DATA field characters
  699. rpack2:    cmp    chrcnt,0        ; any chars expected?
  700.     jle    rpack3            ; le = no, go do checksum
  701.     call    inchr            ; get a character into al. DATA
  702.     jc    rpak2c            ; c = Control-C, timeout, eol
  703.     mov    [bx],ax            ; put char into buffer, with null
  704.     inc    bx            ; point to next free slot
  705.     cmp    al,trans.rsoh        ; start of header char?
  706.     jne    rpak2b            ; ne = no
  707.     jmp    rpack7            ; yes, then go start over
  708. rpak2b:    add    chksum,ax        ; inchr clears AH
  709.     dec    chrcnt            ; one less char expected
  710.     jmp    short rpack2        ; get another data character
  711. rpak2c:    jmp    rpack40            ; Control-C, timeout, EOL
  712.  
  713. rpack3:    mov    byte ptr[bx],0        ; terminate data field
  714.     and    chksum,0fffh    ; keep only lower 12 bits of current checksum
  715.     call    inchr            ; start Checksum bytes
  716.     jc    rpack3b            ; failed
  717.     mov    ah,al
  718.     and    ah,7fh            ; strip high bit
  719.     cmp    ah,trans.rsoh        ; start of header char?
  720.     jne    rpack3a            ; ne = no
  721.     jmp    rpack7            ; yes, then go start over
  722. rpack3a:mov    bx,offset epilog    ; record debugging in epilog buffer
  723.     mov    pktptr,bx        ; start of that buffer, for debug
  724.     mov    deblen,length epilog    ; length of that buffer
  725.     xor    ah,ah
  726.     mov    [bx],ax            ; store checksum
  727.     inc    bx            ; point at next slot
  728.     sub    al,' '            ; unchar() back to binary
  729.     mov    cx,chksum        ; current checksum
  730.     cmp    trans.chklen,2        ; which checksum length is in use?
  731.     je    rpack5            ; e = Two character checksum
  732.     jg    rpack4            ; g = Three char CRC, else one char
  733.     shl    cx,1            ; put two highest digits of al into ah
  734.     shl    cx,1
  735.     and    ch,3            ; want just those two bits
  736.     shr    cl,1            ; put al back in place
  737.     shr    cl,1
  738.     add    cl,ch            ;add two high bits to earlier checksum
  739.     and    cl,03fh            ; chop to lower 6 bits (mod 64)
  740.     cmp    cl,al        ; computed vs received checksum byte (binary)
  741.     je    rpack3b            ; e = equal, so finish up
  742.     or    status,stat_chk        ; say checksum failure
  743. rpack3b:jmp    rpack40
  744.  
  745. rpack7:    jmp    rpack0            ; for the jump out of range
  746.  
  747. rpack4:    mov    tmp,al            ; save value from packet here
  748.     push    bx            ; three character CRC
  749.     mov    cx,[bx-1]        ; save checksum char and next
  750.     mov    temp,cx
  751.     mov    bx,offset prolog+1    ; where data for CRC is, skipping SOH
  752.     xor    dx,dx            ; initial CRC is zero
  753.     call    crcclc            ; calculate the CRC and put into CX
  754.     mov    bx,rtemp
  755.     mov    bx,[bx].datadr        ; data field address
  756.     mov    dx,cx            ; previous CRC
  757.     call    crcclc            ; final CRC is in CX
  758.     pop    bx
  759.     mov    ax,temp
  760.     mov    [bx-1],ax        ; restore char pair from above
  761.     mov    ah,ch            ; cx = 16 bit binary CRC of rcv'd data
  762.     and    ah,0f0h            ; manipulate it here
  763.     shr    ah,1
  764.     shr    ah,1            ; get 4 highest bits
  765.     shr    ah,1
  766.     shr    ah,1            ; shift right 4 bits
  767.     cmp    ah,tmp            ; is what we got == calculated?
  768.     je    rpack4a            ; e = yes
  769.     or    status,stat_chk        ; checksum failure
  770. rpack4a:call    inchr            ; get next character of checksum
  771.     jc    rpack40            ; c = failed
  772.     mov    [bx],ax            ; put into buffer for debug
  773.     inc    bx
  774.     and    al,7fh            ; strip high bit
  775.     cmp    al,trans.rsoh        ; SOH?
  776.     je    rpack7            ; e = yes
  777.     sub    al,' '            ; get back real value
  778. rpack5:    mov    tmp,al            ; save here for now
  779.     push    cx            ; two character checksum
  780.     and    cx,0FC0H        ; get bits 6-11
  781.     mov    ax,cx
  782.     mov    cl,6
  783.     shr    ax,cl            ; shift bits
  784.     pop    cx            ; get back the original
  785.     cmp    al,tmp            ; equal?
  786.     je    rpack5a            ; e = yes
  787.     or    status,stat_chk        ; checksum failure
  788. rpack5a:call    inchr            ; get last character of checksum
  789.     jc    rpack40            ; c = failed
  790.     mov    [bx],ax            ; put into buffer for debug
  791.     inc    bx
  792.     and    al,7fh            ; strip high bit
  793.     cmp    al,trans.rsoh        ; SOH?
  794.     je    rpack7            ; e = yes
  795.     sub    al,' '            ; get back real value    
  796.     and    cx,003FH        ; get bits 0-5
  797.     cmp    al,cl            ; do the last chars match?
  798.     je    rpack40            ; e = yes
  799.     or    status,stat_chk        ; say checksum failure
  800.  
  801. rpack40:mov    byte ptr [bx],0        ; terminate current buffer
  802.     test    status,stat_tmo        ; timeout?
  803.     jz    rpack41            ; z = no
  804.     jmp    rpack60            ; nz = yes
  805. rpack41:test    status,stat_eol        ; premature eol?
  806.     jz    rpack42            ; z = no
  807.     or    status,stat_bad        ; say bad packet overall
  808.     mov    bx,offset epilog     ; start debugging with epilog buffer
  809.     mov    pktptr,bx
  810.     mov    deblen,length epilog    ; length of that buffer
  811.     mov    [bx],ax            ; put it into buffer for debug
  812.     inc    bx
  813.     jmp    short rpack45        ; now try for handshake
  814.  
  815. rpack42:push    bx
  816.     sub    bx,pktptr    ; next char slot - starting address, debugging
  817.     cmp    bx,deblen        ; at length of active debug buffer?
  818.     pop    bx
  819.     jb    rpack43            ; b = no
  820.     call    rdebug            ; yes, dump what we have
  821.     mov    bx,offset epilog    ; and start again with epilog buffer
  822.     mov    pktptr,bx
  823.     mov    deblen,length epilog    ; length of that buffer
  824. rpack43:call    inchr            ; get eol char
  825.     jnc    rpack43a        ; nc = got regular character
  826.     test    status,stat_int        ; interrupted?
  827.     jnz    rpack60            ; nz = yes
  828.     test    status,stat_tmo        ; timeout?
  829.     jnz    rpack43b        ; nz = yes, no char
  830. rpack43a:mov    [bx],ax            ; put into buffer for debug
  831.     inc    bx
  832. rpack43b:and    status,not stat_tmo    ; ignore timeouts on EOL character
  833.     test    status,stat_eol        ; eol char?
  834.     jnz    rpack44            ; nz = yes, got the EOL char
  835.     and    al,7fh            ; strip high bit
  836.     cmp    al,trans.rsoh        ; soh already?
  837.     jne    rpack44            ; ne = no
  838.     jmp    rpack0            ; yes, do debug display and start over
  839.  
  840. rpack44:and    status,not stat_eol     ; desired eol is not an error
  841. rpack45:push    bx            ; test for line turn char
  842.     mov    bx,portval        ;   if doing handshaking
  843.     mov    ah,[bx].hands        ; get desired handshake char
  844.     cmp    [bx].hndflg,0        ; doing half duplex handshaking?
  845.     pop    bx
  846.     je    rpack60            ; e = no
  847.     mov    tmp,ah            ; keep it here
  848.     call    inchr            ; get handshake char
  849.     jnc    rpack45a        ; nc = regular character
  850.     test    status,stat_eol        ; EOL char?
  851.     jnz    rpack45a        ; nz = yes
  852.     jmp    short rpack48        ; timeout or user intervention
  853. rpack45a:and    status,not stat_eol    ; ignore unexpected eol status here
  854.     mov    si,rtemp
  855.     mov    cx,[si].datsize        ; length of receive buffer
  856.     add    cx,[si].datadr        ; starting address of the buffer
  857.     cmp    bx,cx            ; filled buffer yet?
  858.     jae    rpack46            ; ae = yes
  859.     mov    [bx],ax            ; put into buffer for debug
  860.     inc    bx
  861. rpack46:and    al,7fh            ; strip high bit
  862.     cmp    al,trans.rsoh        ; soh already?
  863.     jne    rpack47            ; ne = no
  864.     jmp    rpack0            ; yes, do debug display and start over
  865. rpack47:cmp    al,tmp            ; compare received char with handshake
  866.     jne    rpack45        ; ne = not handshake, try again til timeout
  867. rpack48:and    status,not stat_tmo    ; ignore timeouts on handshake char
  868.  
  869.                     ; Perform logging and debugging now
  870. rpack60:call    rdebug            ; helper procedure
  871.     call    chkcon            ; check console for user interrupt
  872.     test    status,stat_tmo        ; did a timeout get us here?
  873.     jz    rpack61            ; z = no
  874.     mov    si,rtemp
  875.     mov    [si].pktype,'T'        ; yes, say 'T' type packet (timeout)
  876.     test    flags.capflg,logpkt     ; log packets?
  877.     jz    rpack61            ; z = no
  878.     mov    dx,offset msgtmo     ; say timeout in log
  879.     call    captdol
  880. rpack61:test    status,not stat_tmo    ; crunched packet?
  881.     jz    rpack62            ; z = no
  882.     test    flags.capflg,logpkt     ; log packets?
  883.     jz    rpack62            ; z = no
  884.     mov    dx,offset msgbad     ; say crunched pkt in log
  885.     call    captdol
  886.  
  887. rpack62:mov    ax,rpkcnt        ; number of bytes received in packet
  888.     add    fsta.prbyte,ax        ; file total received bytes
  889.     adc    fsta.prbyte+2,0        ; propagate carry to high word
  890.     add    ssta.prbyte,ax        ; session total received bytes
  891.     adc    ssta.prbyte+2,0        ; propagate carry to high word
  892.     add    fsta.prpkt,1        ; file received packet
  893.     adc    fsta.prpkt+2,0        ;  ripple carry
  894.     add    ssta.prpkt,1        ; session received packet
  895.     adc    ssta.prpkt+2,0
  896.     mov    si,rtemp        ; restore pkt pointer
  897.     mov    ah,[si].pktype        ; return packet type in ah
  898.         cmp    ah,prvtyp        ; packet type same as last sent?
  899.     jne    rpack64            ; ne = no
  900.     test    flags.capflg,logpkt     ; log packets?
  901.     jz    rpack63            ; z = no
  902.     mov    dx,offset msgecho     ; say echo in log
  903.     call    captdol
  904. rpack63:test    status,stat_int        ; interrupted?
  905.     jnz    rpack64            ; nz = yes, exit now
  906.     jmp    rpack            ; discard echoed packet and read again
  907.  
  908. rpack64:cmp    status,stat_suc        ; successful so far?
  909.     jne    rpack65            ; ne = no
  910.     cmp    chkparflg,0        ; do parity checking?
  911.     je    rpack64a        ; e = no
  912.     mov    chkparflg,0        ; do only once
  913.     test    badpflag,80h        ; get parity error flagging bit
  914.     jz    rpack64a        ; z = no parity error
  915.     mov    bx,portval
  916.     mov    cl,badpflag        ; get new parity plus flagging bit
  917.     and    cl,7fh            ; strip flagging bit
  918.     mov    [bx].parflg,cl        ; force new parity
  919. rpack64a:clc                ; carry clear for success
  920.     ret
  921. rpack65:stc                ; carry set for failure
  922.     ret                ; failure exit
  923. RPACK    ENDP
  924.  
  925. rdebug    proc    near
  926.     cmp    debflg,0        ; setup debug display yet?
  927.     jne    rdebu1            ; ne = yes
  928.     call    rcvdeb            ; setup display
  929. rdebu1:    test    flags.debug,logpkt    ; in debug mode?
  930.     jnz    rdebu2            ; nz = yes
  931.     test    flags.capflg,logpkt    ; log packets?
  932.     jz    rdebu5            ; z = no
  933. rdebu2:    mov    dx,offset prolog    ; do prolog section
  934.     mov    pktptr,dx
  935.     mov    bx,dx
  936.     call    strlen1            ; get length of prolog section
  937.     jcxz    rdebu3            ; z = empty, try next section
  938.     add    bx,cx            ; point off end
  939.     call    deblin            ; do debug display
  940.     mov    prolog,0        ; clear prolog field
  941. rdebu3:    mov    bx,rtemp        ; do data section
  942.     mov    bx,[bx].datadr
  943.     mov    dx,bx
  944.     mov    pktptr,bx
  945.     call    strlen1            ; get length of data section
  946.     jcxz    rdebu4            ; z = empty, try next section
  947.     add    bx,cx            ; point off end
  948.     call    deblin            ; do debug display
  949. rdebu4:    mov    bx,offset epilog    ; do epilog section
  950.     mov    pktptr,bx
  951.     mov    dx,bx
  952.     call    strlen1            ; get length of epilog section
  953.     jcxz    rdebu5            ; z = empty
  954.     add    bx,cx            ; point off end
  955.     call    deblin            ; do debug display
  956.     mov    epilog,0        ; clear epilog field
  957. rdebu5:    test    flags.debug,logpkt    ; In debug mode?
  958.     jnz    rdebu6            ; nz = yes
  959.     test    flags.capflg,logpkt    ; log packets?
  960.     jz    rdebu7            ; z = no
  961. rdebu6:    cmp    linecnt,0        ; anything on current line?
  962.     je    rdebu7            ; e = no
  963.     mov    dx,offset crlf        ; finish line with cr/lf
  964.     call    captdol            ;  to log file
  965. rdebu7:    ret
  966. rdebug    endp
  967.  
  968. ; Check Console (keyboard). Return carry setif "action" chars: cr for forced
  969. ; timeout, Control-E for force out Error packet, Control-C for quit work now.
  970. ; Return carry clear on Control-X and Control-Z as these are acted upon by
  971. ; higher layers. Consume and ignore anything else.
  972. chkcon:    call    isdev1        ; is stdin a device and not a disk file?
  973.     jnc    chkco5        ; nc = no, a disk file so do not read here
  974.     mov    dl,0ffh
  975.     mov    ah,dconio        ; read console
  976.     int    dos
  977.     jz    chkco5            ; z = nothing there
  978.     and    al,1fh            ; make char a control code
  979.     cmp    al,CR            ; carriage return?
  980.     je    chkco3            ; e = yes, simulate timeout
  981.     cmp    al,'C'-40h        ; Control-C?
  982.     je    chkco1            ; e = yes
  983.     cmp    al,'E'-40h        ; Control-E?
  984.     je    chkco1            ; e = yes
  985.     cmp    al,'X'-40h        ; Control-X?
  986.     je    chkco4            ; e = yes
  987.     cmp    al,'Z'-40h        ; Control-Z?
  988.     je    chkco4        ; record it, take no immmediate action here
  989.     cmp    al,'Q'-40h        ; Control-Q?
  990.     je    chkco6            ; e = yes
  991.     or    al,al            ; scan code being returned?
  992.     jnz    chkco5            ; nz = no, ignore ascii char
  993.     mov    ah,dconio        ; read and discard second byte
  994.     mov    dl,0ffh
  995.     int    dos
  996.     jmp    short chkco5        ; else unknown, ignore
  997. chkco1:    or    al,40h            ; make Control-C-E printable
  998.     mov    flags.cxzflg,al        ; remember what we saw
  999. chkco2:    or    status,stat_int        ; interrupted
  1000.     stc
  1001.     ret                ; act now
  1002. chkco3:    or    status,stat_tmo        ; CR simulates timeout
  1003.     stc
  1004.     ret                ; act now
  1005. chkco4:    or    al,40h            ; make control-X-Z printable
  1006.     mov    flags.cxzflg,al        ; put into flags
  1007.     clc                ; do not act on them here
  1008.     ret
  1009. chkco5:    cmp    flags.cxzflg,'C'    ; control-C intercepted elsewhere?
  1010.     je    chkco2            ; e = yes
  1011.     clc                ; else say no immediate action needed
  1012.     ret
  1013. chkco6:    xchg    ah,al            ; put Control-Q in AH for transmission
  1014.     call    spkout            ; send it now
  1015.     jmp    short chkco5
  1016.  
  1017. getlen    proc    near        ; compute packet length for short & long types
  1018.                 ; returns length in [si].datlen and
  1019.                 ; length type (0, 1, 3) in local byte lentyp
  1020.                 ; returns length of  data + checksum
  1021.     mov     si,rtemp
  1022.     mov    ax,[si].datlen    ; get LEN byte value
  1023.     and    ax,7fh        ; clear unused high byte and parity bit
  1024.  
  1025.     cmp    al,3        ; regular packet has 3 or larger here
  1026.     jb    getln1        ; b = long packet
  1027.     sub    [si].datlen,2    ; minus SEQ and TYPE = DATA + CHKSUM
  1028.     mov    lentyp,3    ; store assumed length type (3 = regular)
  1029.     clc            ; clear carry for success
  1030.     ret
  1031.  
  1032. getln1:    push    cx        ; counter for number of length bytes
  1033.     mov    lentyp,0    ; store assumed length type 0 (long)
  1034.     mov    cx,2        ; two base-95 digits
  1035.     or    al,al        ; is this a type 0 (long packet)?
  1036.     jz    getln2        ; z = yes, go find & check length data
  1037.     mov    lentyp,1    ; store length type (1 = extra long)
  1038.     inc    cx        ; three base 95 digits
  1039.     cmp    al,1        ; is this a type 1 (extra long packet)?
  1040.     je    getln2        ; e = yes, go find & check length data
  1041.     pop    cx
  1042.     or    status,stat_ptl    ; say packet too long (an unknown len code)
  1043.     stc            ; set carry bit to say error
  1044.     ret
  1045. getln2:                ; chk header chksum and recover binary length
  1046.     push    dx        ; save working reg
  1047.     xor    ax,ax        ; clear length accumulator, low part
  1048.     mov    [si].datlen,ax    ; clear final length too
  1049. getln3:    xor    dx,dx        ; ditto, high part
  1050.     mov    ax,[si].datlen    ; length to date
  1051.     mul    ninefive    ; multiply accumulation (in ax) by 95
  1052.     mov    [si].datlen,ax    ; save results
  1053.     push    cx
  1054.     call    inchr        ; read another serial port char into al
  1055.     pop    cx
  1056.     jc    getln4        ; c = failure
  1057.     xor    ah,ah
  1058.     mov    [bx],al        ; store in buffer
  1059.     inc    bx
  1060.     add    chksum,ax
  1061.     sub    al,20h        ; subtract space, apply unchar()
  1062.     mov    si,rtemp
  1063.     add    [si].datlen,ax    ; add to overall length count
  1064.     loop    getln3        ; cx preset earlier for type 0 or type 1
  1065.     mov    dx,chksum    ; get running checksum
  1066.     shl    dx,1        ; get two high order bits into dh
  1067.     shl    dx,1
  1068.     and    dh,3        ; want just these two bits
  1069.     shr    dl,1        ; put low order part back
  1070.     shr    dl,1
  1071.     add    dl,dh        ; add low order byte to two high order bits
  1072.     and    dl,03fh        ; chop to lower 6 bits (mod 64)
  1073.     add    dl,20h        ; apply tochar()
  1074.     push    dx
  1075.     call    inchr        ; read another serial port char
  1076.     pop    dx
  1077.     jc    getln4        ; c = failure
  1078.     xor    ah,ah
  1079.     mov    [bx],al        ; store in buf for debug
  1080.     inc    bx
  1081.     add    chksum,ax
  1082.     cmp    dl,al        ; our vs their checksum, same?
  1083.     je    getln5        ; e = checksums match, success
  1084. getln4:    or    status,stat_chk    ; checksum failure
  1085.     pop    dx        ; unsave regs (preserves flags)
  1086.     pop    cx
  1087.     stc            ; else return carry set for error
  1088.     ret
  1089. getln5:    pop    dx        ; unsave regs (preserves flags)
  1090.     pop    cx
  1091.     clc            ; clear carry (say success)
  1092.     ret
  1093. getlen    endp
  1094.  
  1095. ; Get char from serial port into al, with timeout and console check.
  1096. ; Return carry set if timeout or console char or EOL seen,
  1097. ; return carry clear and char in AL for other characters.
  1098. ; Sets status of stat_eol if EOL seen.
  1099. ; Fairflg allows occassional reads from console before looking at serial port.
  1100. inchr    proc    near
  1101.     mov    timeit,0    ; reset timeout flag (do each char separately)
  1102.     push    bx        ; save a reg
  1103.     cmp    fairflg,maxpack/4 ; look at console first every now and then
  1104.     jbe    inchr1        ; be = not console's turn yet
  1105.     mov    fairflg,0    ; reset fairness flag for next time
  1106.     call    chkcon        ; check console
  1107.     jnc    inchr1        ; nc = nothing to interrupt us
  1108.     pop    bx        ; clean stack
  1109.     ret            ; return failure for interruption
  1110.  
  1111. inchr1:    call    prtchr1        ; read a serial port character
  1112.     jc    inchr2        ; c = nothing there
  1113.     pop    bx        ; here with char in al from port
  1114.     mov    ah,al        ; copy char to temp place AH
  1115.     and    ah,7fh        ; strip parity bit from work copy
  1116.     and    al,parmsk    ; apply 7/8 bit parity mask
  1117.     or    ah,ah        ; null char?
  1118.     jz    inchr        ; ignore the null, read another char
  1119.     cmp    ah,del        ; ascii del byte?
  1120.     je    inchr        ; e = yes, ignore it too
  1121.     inc    rpkcnt        ; count received byte
  1122.     cmp    al,trans.rign    ; char in al to be ignored?
  1123.     je    inchr        ; e = yes, do so
  1124.     cmp    ah,'C'-40h    ; Control-C from comms line?
  1125.     jne    inchr6        ; ne = no
  1126.     cmp    ah,prevchar    ; was previous char also Control-C?
  1127.     jne    inchr6        ; ne = no
  1128.     cmp    ah,trans.rsoh    ; could this also be an SOH?
  1129.     je    inchr6        ; e = yes, do not exit
  1130.     cmp    ah,trans.reol    ; could this also be an EOL?
  1131.     je    inchr6        ; e = yes
  1132.     test    denyflg,finflg    ; is FIN enabled?
  1133.     jnz    inchr6        ; nz = no, ignore server exit cmd
  1134.     mov    flags.cxzflg,'C'; set Control-C flag
  1135.     or    status,stat_int+stat_eol ; say interrupted and End of Line
  1136.     mov    al,ah        ; use non-parity version
  1137.     xor    ah,ah        ; always return with high byte clear
  1138.     stc            ; exit failure
  1139.     ret
  1140. inchr6:    mov    prevchar,ah    ; remember current as previous char
  1141.     cmp    ah,trans.reol    ; eol char we want?
  1142.     je    inchr7        ; e = yes, ret with carry set
  1143.     xor    ah,ah        ; always return with high byte clear
  1144.     clc            ; char is in al
  1145.     ret
  1146. inchr7:    or    status,stat_eol    ; set status appropriately
  1147.     mov    al,ah        ; use non-parity version
  1148.     xor    ah,ah        ; always return with high byte clear
  1149.     stc            ; set carry to say eol seen
  1150.     ret            ; and return qualified failure
  1151.     
  1152. inchr2:    call    chkcon        ; check console
  1153.     jnc    inchr2a        ; nc = nothing to interrupt us
  1154.     pop    bx        ; clean stack
  1155.     ret            ; return failure for interruption
  1156.  
  1157. inchr2a:cmp    flags.timflg,0    ; are timeouts turned off?
  1158.     je    inchr1        ; e = yes, just check for more input
  1159.     cmp    trans.stime,0    ; doing time outs?
  1160.     jne    inchr2b        ; ne = yes
  1161.     jmp    inchr1        ; go check for more input
  1162. inchr2b:push    cx        ; save regs
  1163.     push    dx        ; Stolen from Script code
  1164.     cmp    timeit,0    ; have we gotten time of day for first fail?
  1165.     jne    inchr4        ; ne = yes, just compare times
  1166.     mov    ah,gettim    ; get DOS time of day
  1167.     int    dos        ; ch = hh, cl = mm, dh = ss, dl = 0.01 sec
  1168.     xchg    ch,cl        ; get ordering of low byte = hours, etc
  1169.     mov    word ptr rptim,cx ; hours and minutes
  1170.     xchg    dh,dl
  1171.     mov    word ptr rptim+2,dx ; seconds and fraction
  1172.     mov    bl,timeval    ; our desired timeout interval (seconds)
  1173.     xor    bh,bh        ; one byte's worth
  1174.     mov    temp,bx        ; work area
  1175.     mov    bx,2           ; start with seconds field
  1176. inchr3: mov    ax,temp        ; desired timeout interval, working copy
  1177.     add    al,rptim[bx]    ; add current tod digit interval
  1178.     adc    ah,0
  1179.     xor    dx,dx        ; clear high order part thereof
  1180.     div    sixzero        ; compute number of minutes or hours
  1181.     mov    temp,ax        ; quotient, for next time around
  1182.     mov    rptim[bx],dl    ; put normalized remainder in timeout tod
  1183.     dec    bx        ; look at next higher order time field
  1184.     or    bx,bx        ; done all time fields?
  1185.     jge    inchr3        ; ge = no
  1186.     cmp    rptim[0],24    ; normalize hours
  1187.     jl    inchr3a        ; l = not 24 hours or greater
  1188.     sub    rptim[0],24    ; discard part over 24 hours
  1189. inchr3a:mov    timeit,1    ; say have tod of timeout
  1190.  
  1191. inchr4:    mov    ah,gettim    ; compare present tod versus timeout tod
  1192.     int    dos        ; get the time of day
  1193.     sub    ch,rptim    ; hours difference, ch = (now - timeout)
  1194.     je    inchr4b        ; e = same, check mmss.s
  1195.     jl    inchr4d        ; l = we are early
  1196.     cmp    ch,12        ; hours difference, large or small?
  1197.     jge    inchr4d        ; ge = we are early
  1198.     jl    inchr4c        ; l = we are late, say timeout
  1199. inchr4b:cmp    cl,rptim+1    ; minutes, hours match
  1200.     jb    inchr4d        ; b = we are early
  1201.     ja    inchr4c        ; a = we are late
  1202.     cmp    dh,rptim+2    ; seconds, hours and minutes match
  1203.     jb    inchr4d        ; b = we are early
  1204.     ja    inchr4c        ; a = we are late
  1205.     cmp    dl,rptim+3    ; hundredths of seconds, hhmmss match
  1206.     jb    inchr4d        ; b = we are early
  1207. inchr4c:or    status,stat_tmo    ; say timeout
  1208. ;    cmp    flowon,0    ; using xon/xoff flow control?
  1209. ;    je    inchr4e        ; e = no
  1210. ;    mov    ah,flowon    ; send host an xon in case it's stuck
  1211. ;    call    outchr1        ;   with a stray xoff not from us
  1212. inchr4e:pop    dx
  1213.     pop    cx
  1214.     pop    bx
  1215.     stc            ; set carry bit
  1216.     ret            ; failure
  1217. inchr4d:pop    dx
  1218.     pop    cx
  1219.     jmp    inchr1        ; not timed out yet
  1220. inchr    endp
  1221.  
  1222.  
  1223. ; sleep for the # of seconds in al
  1224. ; Preserve all regs. Added console input forced timeout 21 March 1987 [jrd]
  1225. sleep    proc    far
  1226.     push    ax
  1227.     push    cx
  1228.     push    dx
  1229.     push    ax        ; save argument
  1230.     mov    ah,gettim    ; DOS tod (ch=hh, cl=mm, dh=ss, dl=.s)
  1231.     int    dos        ; get current time
  1232.     pop    ax        ; restore desired # of seconds
  1233.     add    dh,al        ; add # of seconds
  1234. sleep1:    cmp    dh,60        ; too big for seconds?
  1235.     jb    sleep2        ; no, keep going
  1236.     sub    dh,60        ; yes, subtract a minute's overflow
  1237.     inc    cl        ; and add one to minutes field
  1238.     cmp    cl,60        ; did minutes overflow?
  1239.     jb    sleep1        ; no, check seconds again
  1240.     sub    cl,60        ; else take away an hour's overflow
  1241.     inc    ch        ; add it back in hours field
  1242.     jmp    short sleep1    ; and keep checking
  1243. sleep2:    mov    time,cx        ; store desired ending time,  hh,mm
  1244.     mov    time+2,dx    ; ss, .s
  1245. sleep3:    call    chkcon        ; check console for user timeout override
  1246.     jc    short sleep5    ; c = have override
  1247.     mov    ah,gettim    ; get time
  1248.     int    dos        ; from dos
  1249.     sub    ch,byte ptr time+1 ; hours difference, ch = (now - timeout)
  1250.     je    sleep4        ; e = hours match, check mmss.s
  1251.     jl    sleep3        ; l = we are early
  1252.     cmp    ch,12        ; hours difference, large or small?
  1253.     jge    sleep3        ; ge = we are early
  1254.     jl    sleep5        ; l = we are late, exit now
  1255. sleep4:    cmp    cl,byte ptr time ; check minutes, hours match
  1256.     jb    sleep3        ; b = we are early
  1257.     ja    sleep5        ; a = over limit, time to exit
  1258.     cmp    dx,time+2    ; check seconds and fraction, hhmm match
  1259.     jb    sleep3        ; b = we are early
  1260. sleep5:    pop    dx
  1261.     pop    cx
  1262.     pop    ax
  1263.     ret
  1264. sleep    endp
  1265.                 ; Packet Debug display routines
  1266. rcvdeb:    test    flags.debug,logpkt ; In debug mode?
  1267.     jnz    rcvde1        ; nz = yes
  1268.     test    flags.capflg,logpkt ; log packets?
  1269.     jnz    rcvde1        ; nz = yes
  1270.     ret            ; no
  1271. rcvde1:    mov    debflg,'R'    ; say receiving
  1272.     jmp    short deb1
  1273.  
  1274. snddeb:    test    flags.debug,logpkt ; In debug mode?
  1275.     jnz    sndde1        ; nz = yes
  1276.     test    flags.capflg,logpkt ; log packets?
  1277.     jnz    sndde1        ; yes
  1278.     ret            ; no
  1279. sndde1:    mov    debflg,'S'    ; say sending
  1280.  
  1281. deb1:    push    ax        ; Debug. Packet display
  1282.     push    bx
  1283.     push    cx        ; save some regs
  1284.     push    dx
  1285.     push    di
  1286.     test    flags.debug,logpkt    ; is debug active (vs just logging)?
  1287.     jz    deb1d        ; z = no, just logging
  1288.     cmp    fmtdsp,0    ; non-formatted display?
  1289.     je    deb1d        ; e = yes, skip extra line clearing
  1290.     cmp    debflg,'R'    ; receiving?
  1291.     je    deb1a        ; e = yes
  1292.     call    sppos1        ; spack: cursor position
  1293.     jmp    short deb1b
  1294. deb1a:    call    rppos1        ; rpack: cursor position
  1295. deb1b:    call    clearl1        ; clear the line
  1296.         mov    dx,offset crlf
  1297.         mov    ah,prstr    ; display
  1298.         int    dos
  1299.         call    clearl1        ; clear debug line and line beneath
  1300.     cmp    debflg,'R'    ; receiving?
  1301.     je    deb1c        ; e = yes
  1302.     call    sppos1        ; reposition cursor for spack:
  1303.     jmp    short deb1d
  1304. deb1c:    call    rppos1        ; reposition cursor for rpack:
  1305. deb1d:    mov    dx,offset spmes    ; spack: message
  1306.     cmp    debflg,'R'
  1307.     jne    deb2        ; ne = sending
  1308.     mov    dx,offset rpmes    ; rpack: message
  1309. deb2:    call    captdol        ; record dollar terminated string in Log file
  1310.     mov    linecnt,7    ; number of columns used so far
  1311.     pop    di
  1312.     pop    dx
  1313.     pop    cx
  1314.     pop    bx
  1315.     pop    ax
  1316.     ret
  1317.  
  1318. ; Display/log packet chars processed so far.
  1319. ; Displays chars from pktptr to bx-1, both are pointers.
  1320. ; Enter with bx = offset of next new char. All registers preserved
  1321. deblin:    test    flags.debug,logpkt ; In debug mode?
  1322.     jnz    debln0        ; nz = yes
  1323.     test    flags.capflg,logpkt ; log packets?
  1324.     jnz    debln0        ; nz = yes
  1325.     ret            ; else    nothing to do
  1326. debln0:    push    cx
  1327.     push    dx
  1328.     push    di
  1329.     mov    di,pktptr    ; starting place for debug analysis
  1330.     mov    cx,bx        ; place for next new char
  1331.     sub    cx,di        ; minus where we start = number chars to do
  1332.     or    cx,cx
  1333.     jle    debln5        ; le = nothing to do
  1334. debln2:
  1335.     push    cx        ; save loop counter
  1336.     cmp    linecnt,70
  1337.          jb    debln3        ; b = not yet, get next data char
  1338.     mov    dx,offset crlf    ; break line with cr/lf
  1339.     call    captdol        ; and in log file
  1340.     mov    linecnt,0    ; setup for next line
  1341. debln3:    mov    dl,[di]        ; get char
  1342.     test    dl,80h        ; high bit set?
  1343.     jz    debln3b        ; z = no
  1344.     push    dx        ; save char in dl
  1345.     mov    dl,7eh        ; show tilde char for high bit set
  1346.     call    captchr        ; record in Log file
  1347.     inc    linecnt        ; count displayed column
  1348.     cmp    linecnt,70    ; exhausted line count yet?
  1349.     jb    debln3a        ; b = not yet
  1350.     mov    dx,offset crlf    ; break line with cr/lf
  1351.     call    captdol        ; and in log file
  1352.     mov    linecnt,0    ; setup for next line
  1353. debln3a:pop    dx
  1354.     and    dl,7fh        ; get lower seven bits here
  1355. debln3b:cmp    dl,' '        ; control char?
  1356.     jae    debln4        ; ae = no
  1357.     add    dl,40h        ; uncontrollify the char
  1358.     push    dx        ; save char in dl
  1359.     mov    dl,5eh        ; show caret before control code
  1360.     call    captchr        ; record in Log file
  1361.     inc    linecnt        ; count displayed column
  1362.     cmp    linecnt,70    ; exhausted line count yet?
  1363.     jb    debln3c        ; b = not yet
  1364.     mov    dx,offset crlf    ; break line with cr/lf
  1365.     call    captdol        ; and in log file
  1366.     mov    linecnt,0    ; setup for next line
  1367. debln3c:pop    dx        ; recover char in dl
  1368.  
  1369. debln4:    call    captchr        ; record char in dl in the log file
  1370.     inc    di        ; done with this char, point to next
  1371.     inc    linecnt        ; one more column used on screen
  1372.     pop    cx        ; recover loop counter
  1373.     loop    debln2        ; get next data char
  1374. debln5:    pop    di
  1375.     pop    dx
  1376.     pop    cx
  1377.     ret
  1378.  
  1379.  
  1380. captdol    proc    near        ; write dollar sign terminated string in dx
  1381.                 ; to the capture file (Log file).
  1382.     push    ax        ; save regs
  1383.     push    si
  1384.     mov    si,dx        ; point to start of string
  1385.     cld
  1386. captdo1:lodsb            ; get a byte into al
  1387.     cmp    al,'$'        ; at the end yet?
  1388.     je    captdo3        ; e = yes
  1389.     or    al,al        ; asciiz?
  1390.     jz    captdo3        ; z = yes, this is also the end
  1391.     mov    dl,al
  1392.     test    flags.debug,logpkt ; debug display active?
  1393.     jz    captdo2        ; z = no
  1394.     mov    ah,conout
  1395.     int    dos        ; display char in dl
  1396. captdo2:test    flags.capflg,logpkt ; logging active?
  1397.     jz    captdo1        ; z = no
  1398.     mov    al,dl        ; where pktcpt wants it
  1399.     call    pktcpt1        ; record the char, pktcpt is in msster.asm
  1400.     jmp    short captdo1    ; repeat until dollar sign is encountered
  1401. captdo3:pop    si
  1402.     pop    ax
  1403.     ret
  1404. captdol    endp
  1405.  
  1406. captchr    proc    near        ; record char in dl into the Log file
  1407.     push    ax
  1408.     test    flags.debug,logpkt ; debug display active?
  1409.     jz    captch1        ; z = no
  1410.     mov    ah,conout
  1411.     int    dos        ; display char in dl
  1412. captch1:test    flags.capflg,logpkt ; logging active?
  1413.     jz    captch2        ; z = no
  1414.     mov    al,dl        ; where pktcpt wants it
  1415.     call    pktcpt1        ; record the char, pktcpt is in msster.asm
  1416. captch2:pop    ax
  1417.     ret
  1418. captchr    endp
  1419.  
  1420. parchk    proc    near            ; check parity of pkt prolog chars
  1421.     cmp    chkparflg,0        ; ok to check parity?
  1422.     jne    parchk0            ; ne = yes
  1423.     ret
  1424. parchk0:push    ax
  1425.     push    bx
  1426.     push    cx
  1427.     push    dx
  1428.     mov    bx,pktptr        ; where packet prolog is stored now
  1429.     mov    ax,[bx]            ; first two prolog chars
  1430.     or    ax,[bx+2]        ; next two
  1431.     test    ax,8080h        ; parity bit set?
  1432.     jz    parchk7            ; z = no
  1433.     mov    parmsk,7fh        ; set parity mask for 7 bits
  1434.     cmp    badpflag,0        ; said bad parity once this packet?
  1435.     jne    parchk7            ; ne = yes
  1436.     mov    cx,4            ; do all four protocol characters
  1437.     xor    dx,dx            ; dl=even parity cntr, dh=odd parity
  1438. parchk1:mov    al,[bx]            ; get a char
  1439.     inc    bx            ; point to next char
  1440.     or    al,al            ; sense parity
  1441.     jpo    parchk2            ; po = odd parity
  1442.     inc    dl            ; count even parity
  1443.     jmp    short parchk3
  1444. parchk2:inc    dh            ; count odd parity
  1445. parchk3:loop    parchk1            ; do all four chars
  1446.     cmp    dl,4            ; got four even parity chars?
  1447.     jne    parchk4            ; ne = no
  1448.     mov    badpflag,parevn+80h    ; say even parity and flagging bit
  1449.     mov    dx,offset msgbadpare    ; say using even parity
  1450.     jmp    short parchk6
  1451. parchk4:cmp    dh,4            ; got four odd parity chars?
  1452.     jne    parchk5            ; ne = no
  1453.     mov    badpflag,parodd+80h    ; say odd parity and flagging bit
  1454.     mov    dx,offset msgbadparo    ; say using odd parity
  1455.     jmp    short parchk6
  1456. parchk5:mov    badpflag,parmrk+80h    ; say mark parity and flagging bit
  1457.     mov    dx,offset msgbadparm    ; say using mark parity
  1458. parchk6:call    ermsg1
  1459.     call    captdol            ; write in log file too
  1460. parchk7:pop    dx
  1461.     pop    cx
  1462.     pop    bx
  1463.     pop    ax
  1464.     ret
  1465. parchk    endp
  1466.  
  1467. ; General packet buffer structure manipulation routines. The packet buffers
  1468. ; consist of a arrays of words, bufuse and buflist, an array of pktinfo
  1469. ; structure packet descriptors, and a subdivided main buffer named "bufbuf".
  1470. ; Each pktinfo member describes a packet by holding the address (offset within
  1471. ; segment data) of the data field of a packet (datadr), the length of that
  1472. ; field in bytes (datsize), the number of bytes currently occupying that field
  1473. ; (datlen), the packet sequence number, an ack-done flag byte, and the number
  1474. ; of retries of the packet.
  1475. ; The data field is a portion of main buffer "bufbuf" with space for an extra
  1476. ; null terminator byte required by the packet routines rpack and spack. It
  1477. ; is sectioned into trans.windo buffers by procedure makebuf.
  1478. ; Bufuse is an array holding an in-use flag for each pktinfo member; 0 means
  1479. ; the member is free, otherwise a caller has allocated the member via getbuf.
  1480. ; Buflist holds the address (offset in segment data) of each pktinfo member,
  1481. ; for rapid list searching.
  1482. ;
  1483. ; Packet structures are constructed and initialized by procedure makebuf.
  1484. ; Other procedures below access the members in various ways. Details of
  1485. ; buffer construction should remain local to these routines.
  1486. ; Generally, SI is used to point to a pktinfo member and AL holds a packet
  1487. ; sequence number (0 - 63 binary). BX and CX are used for some status reports.
  1488. ;
  1489. ;  bufuse    buflist            pktlist (group of pktinfo members)
  1490. ;  -------    -------        -------------------------------------------
  1491. ; 0 for unused              | datadr,datlen,datsize,seqnum,ackdone,numtry |
  1492. ;            pointers to ->+ datadr,datlen,datsize,seqnum,ackdone,numtry |
  1493. ; 1 for used              | datadr,datlen,datsize,seqnum,ackdone,numtry |
  1494. ;                        etc
  1495. ;
  1496. ; Construct new buffers, cleared, by subdividing main buffer "bufbuf"
  1497. ; according to the number of windows (variable trans.windo). Makes these
  1498. ; buffers available to getbuf and other manipulation routines. All regs
  1499. ; are preserved.
  1500. makebuf    proc    far
  1501.     push    ax
  1502.     push    bx
  1503.     push    cx
  1504.     push    dx
  1505.     push    si
  1506.     mov    ax,maxpack        ; size of main packet buffer (bufbuf)
  1507.     mov    cl,trans.windo        ; number of window slots
  1508.     xor    ch,ch
  1509.     cmp    cx,1            ; 0 or 1 window slots = initial slot
  1510.     jae    makebu1            ; a = more than one, compute
  1511.     inc    cx
  1512.     jmp    short makebu2        ; save a division by one
  1513. makebu1:xor    dx,dx
  1514.     div    cx            ; size of windowed buffer to ax
  1515. makebu2:mov    dx,ax            ; keep buffer size in dx
  1516.     mov    bufnum,cx        ; number of buffers
  1517.     mov    ax,offset bufbuf    ; where buffers start
  1518.     mov    si,offset pktlist    ; where pktinfo group starts
  1519.     xor    bx,bx            ; index (words)
  1520. makebu3:mov    bufuse[bx],0        ; say buffer slot is not used yet
  1521.     mov    buflist[bx],si        ; pointer to pktinfo member
  1522.     mov    [si].datadr,ax        ; address of data field
  1523.     mov    [si].datsize,dx        ; data buffer size
  1524.     mov    [si].numtry,0        ; clear number tries for this buffer
  1525.     mov    [si].ackdone,0        ; not acked yet
  1526.     mov    [si].seqnum,0        ; a dummy sequence number
  1527.     add    si,size pktinfo        ; next pktinfo member
  1528.     add    ax,dx            ; pointer to next buffer
  1529.     inc    ax            ; leave space for null pointer
  1530.     add    bx,2            ; next buflist slot
  1531.     loop    makebu3            ; make another structure member
  1532.     mov    windused,0        ; no slots used yet
  1533.     pop    si
  1534.     pop    dx
  1535.     pop    cx
  1536.     pop    bx
  1537.     pop    ax
  1538.     ret
  1539. makebuf    endp
  1540.  
  1541. ; Allocate a buffer. Return carry clear and SI pointing at fresh pktinfo
  1542. ; structure, or if failure return carry set and all regs preserved.
  1543. getbuf    proc    far
  1544.     push    ax
  1545.     push    cx
  1546.     push    si
  1547.     xor    si,si            ; index
  1548.     mov    cx,bufnum        ; number of buffers
  1549.     jcxz    getbuf2            ; 0 means none, error
  1550. getbuf1:cmp    bufuse[si],0        ; is this slot in use?
  1551.     je    getbuf3            ; e = no, grab it
  1552.     add    si,2            ; try next slot
  1553.     loop    getbuf1            ; fall through on no free buffers
  1554. getbuf2:pop    si            ; get here if all are in use
  1555.     pop    cx
  1556.     pop    ax
  1557.     stc                ; return failure, si preserved
  1558.     ret
  1559.  
  1560. getbuf3:mov    bufuse[si],1        ; mark buffer as being in use
  1561.     inc    windused        ; one more slot in use
  1562.     mov    si,buflist[si]        ; address of pktinfo member
  1563.     mov    al,pktnum        ; next sequence number to be used
  1564.     mov    [si].seqnum,al        ; use it as sequence number
  1565.     mov    [si].datlen,0        ; no data in packet
  1566.     mov    [si].numtry,0        ; clear number tries for this buffer
  1567.     mov    [si].ackdone,0        ; not acked yet
  1568.     pop    cx            ; discard originally saved si
  1569.     pop    cx
  1570.     pop    ax
  1571.     clc                ; return success, buffer ptr in si
  1572.     ret
  1573. getbuf    endp
  1574.  
  1575. ; Release all buffers (just marks them as free).
  1576.  
  1577. bufclr    proc    far
  1578.     push    ax
  1579.     push    cx
  1580.     push    di
  1581.     push    es
  1582.     push    ds
  1583.     pop    es
  1584.     mov    cx,maxwind        ; max number of buffers
  1585.     xor    ax,ax
  1586.     mov    di,offset bufuse    ; buffer in-use list
  1587.     cld
  1588.     rep    stosw            ; store zeros to clear the buffers
  1589.     mov    windused,0        ; number now used (none)
  1590.     pop    es
  1591.     pop    di
  1592.     pop    cx
  1593.     pop    ax
  1594.     ret
  1595. bufclr    endp
  1596.  
  1597. ; Release buffer whose pktinfo pointer is in SI.
  1598. ; Return carry clear if success, or carry set if failure.
  1599. bufrel    proc    far
  1600.     push    bx
  1601.     push    cx
  1602.     mov    cx,bufnum        ; number of buffers
  1603.     xor    bx,bx
  1604. bufrel1:cmp    buflist[bx],si        ; compare addresses, match?
  1605.     je    bufrel2            ; e = yes, found it
  1606.     add    bx,2
  1607.     loop    bufrel1
  1608.     pop    cx
  1609.     pop    bx
  1610.     stc                ; no such buffer
  1611.     ret
  1612. bufrel2:mov    bufuse[bx],0        ; say buffer is no longer in use
  1613.     dec    windused        ; one less used buffer
  1614.     pop    cx
  1615.     pop    bx
  1616.     clc
  1617.     ret
  1618. bufrel    endp
  1619.  
  1620. ; Returns in BX the "packet pointer" for the buffer with the same seqnum as
  1621. ; provided in AL. Returns carry set if no match found. Modifies BX.
  1622. pakptr    proc    far
  1623.     push    cx
  1624.     push    di
  1625.     mov    cx,bufnum        ; number of buffers
  1626.     xor    di,di            ; buffer index for tests
  1627. pakptr1:cmp    bufuse[di],0        ; is buffer vacant?
  1628.     je    pakptr2            ; e = yes, ignore
  1629.     mov    bx,buflist[di]        ; bx = address of pktinfo member
  1630.     cmp    al,[bx].seqnum        ; is this the desired sequence number?
  1631.     je    pakptr3            ; e = yes
  1632. pakptr2:add    di,2            ; next buffer index
  1633.     loop    pakptr1            ; do next test
  1634.     xor    bx,bx            ; say no pointer
  1635.     stc                ; set carry for failure
  1636.     pop    di
  1637.     pop    cx
  1638.     ret
  1639. pakptr3:clc                ; success, BX has buffer pointer
  1640.     pop    di
  1641.     pop    cx
  1642.     ret
  1643. pakptr    endp
  1644.  
  1645. ; Returns in AH count of packets with a given sequence number supplied in AL
  1646. ; and returns in BX the packet pointer of the last matching entry.
  1647. ; Used to detect duplicated packets.
  1648. pakdup    proc    far
  1649.     push    cx
  1650.     push    dx
  1651.     push    di
  1652.     mov    cx,bufnum        ; number of buffers
  1653.     xor    di,di            ; buffer index for tests
  1654.     xor    ah,ah            ; number of pkts with seqnum in al
  1655.     mov    dx,-1            ; a bad pointer
  1656. pakdup1:cmp    bufuse[di],0        ; is buffer vacant?
  1657.     je    pakdup2            ; e = yes, ignore
  1658.     mov    bx,buflist[di]        ; bx = address of pktinfo member
  1659.     cmp    al,[bx].seqnum        ; is this the desired sequence number?
  1660.     jne    pakdup2            ; ne = no
  1661.     mov    dx,bx            ; yes, remember last pointer
  1662.     inc    ah            ; count a found packet
  1663. pakdup2:add    di,2            ; next buffer index
  1664.     loop    pakdup1            ; do next test
  1665.     mov    bx,dx            ; return last matching member's ptr
  1666.     pop    di
  1667.     pop    dx
  1668.     pop    cx
  1669.     or    ah,ah            ; any found?
  1670.     jz    pakdup3            ; z = no
  1671.     clc                ; return success
  1672.     ret
  1673. pakdup3:stc                ; return failure
  1674.     ret
  1675. pakdup    endp
  1676.     
  1677. ; Find sequence number of first free window slot and return it in AL,
  1678. ; Return carry set and al = windlow if window is full (no free slots).
  1679. firstfree proc    far
  1680.     mov    al,windlow        ; start looking at windlow
  1681.     mov    ah,al
  1682.     add    ah,trans.windo
  1683.     and    ah,3fh            ; ah = 1+top window seq number, mod 64
  1684. firstf1:push    bx
  1685.     call    pakptr            ; buffer in use for seqnum in AL?
  1686.     pop    bx
  1687.     jc    firstf2            ; c = no, seq number in not in use
  1688.     inc    al            ; next sequence number
  1689.     and    al,3fh            ; modulo 64
  1690.     cmp    al,ah            ; done all yet?
  1691.     jne    firstf1            ; ne = no, do more
  1692.     mov    al,windlow        ; a safety measure
  1693.     stc                ; carry set to say no free slots
  1694.     ret
  1695. firstf2:clc                ; success, al has first free seqnum
  1696.     ret
  1697. firstfree endp
  1698.  
  1699. ; Check sequence number for lying in the current or previous window or
  1700. ; outside either window.
  1701. ; Enter with sequence number of received packet in [si].seqnum.
  1702. ; Returns:
  1703. ;    carry clear and cx =  0 if [si].seqnum is within the current window,
  1704. ;    carry set   and cx = -1 if [si].seqnum is inside previous window,
  1705. ;    carry set   and cx = +1 if [si].seqnum is outside any window.
  1706. chkwind    proc    far
  1707.     mov    ch,[si].seqnum        ; current packet sequence number
  1708.     mov    cl,trans.windo        ; number of window slots
  1709.     sub    ch,windlow        ; ch = distance from windlow
  1710.     jc    chkwin1            ; c = negative result
  1711.     cmp    ch,cl            ; span greater than # window slots?
  1712.     jb    chkwinz            ; b = no, in current window
  1713.     sub    ch,64            ; distance measured the other way
  1714.     neg    ch
  1715.     cmp    ch,cl            ; more than window size?
  1716.     ja    chkwinp            ; a = yes, outside any window
  1717.     jmp    short chkwinm        ; else in previous window
  1718.  
  1719.                     ; sequence number less than windlow
  1720. chkwin1:neg    ch            ; distance, positive, cl >= ch
  1721.     cmp    ch,cl            ; more than window size?
  1722.     ja    chkwin2            ; a = yes, maybe this window
  1723.     jmp    short chkwinm        ; no, in previous window
  1724.  
  1725. chkwin2:sub    ch,64            ; distance measured the other way
  1726.     neg    ch
  1727.     cmp    ch,cl            ; greater than window size?
  1728.     jb    chkwinz            ; b = no, in current window
  1729.                     ; else outside any window
  1730.  
  1731. chkwinp:mov    cx,1            ; outside any window
  1732.     stc                ; carry set for outside current window
  1733.     ret
  1734. chkwinz:xor    cx,cx            ; inside current window
  1735.     clc                ; carry clear, inside current window
  1736.     ret
  1737. chkwinm:mov    cx,-1            ; in previous window
  1738.     stc                ; carry set for outside current window
  1739.     ret
  1740. chkwind    endp
  1741.  
  1742. code1    ends
  1743.     end
  1744.